package com.sright.bcard.common.biz.manager.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.green.model.v20180509.ImageSyncScanRequest;
import com.aliyuncs.green.model.v20180509.TextScanRequest;
import com.aliyuncs.green.model.v20180509.VideoAsyncScanRequest;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.HttpResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.sright.bcard.common.biz.manager.ContentCheckManager;
import com.sright.bcard.common.service.share.dto.common.*;
import com.sright.bcard.common.service.share.exception.base.BusinessErrorException;
import com.sright.bcard.common.service.share.exception.code.BusinessCode;
import com.sright.bcard.content.dal.dao.ContentCheckRecordDAO;
import com.sright.bcard.content.dal.dao.MaterialDAO;
import com.sright.bcard.content.dal.dao.TextCheckRecordDAO;
import com.sright.bcard.content.dal.entity.ContentCheckRecordDO;
import com.sright.bcard.content.dal.entity.MaterialDO;
import com.sright.bcard.content.dal.entity.TextCheckRecordDO;
import com.sright.bcard.enterprise.share.service.MaterialService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.*;

@Component
@Slf4j
public class ContentCheckManagerImpl implements ContentCheckManager {

    @Value("${aliyun.miniapp.transcode.access-key-id}")
    private String AccessKeyId;

    @Value("${aliyun.miniapp.transcode.access-key-secret}")
    private String AccessKeySecret;

    @Value("${VIDEO_CHECK_CALLBACK_URL}")
    private String CallBack;

    @Value("${VIDEO_URL}")
    private String VideoUrl;

    @Value("${IMAGE_URL}")
    private String ImageUrl;

    @Autowired
    private MaterialDAO materialDAO;

    @Autowired
    private MaterialService materialService;

    @Autowired
    private ContentCheckRecordDAO contentCheckRecordDAO;

    @Autowired
    private TextCheckRecordDAO textCheckRecordDAO;

    public IAcsClient getClient() {
        IClientProfile profile = DefaultProfile
                .getProfile("cn-shanghai", AccessKeyId, AccessKeySecret);
        try {
            DefaultProfile
                    .addEndpoint("cn-shanghai", "cn-shanghai", "Green", "green.cn-shanghai.aliyuncs.com");
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return new DefaultAcsClient(profile);
    }

    @Override
    public String textCheck(List<String> contentList,Long userId,Integer sourceId) {
        IAcsClient client = getClient();
        TextScanRequest textScanRequest = new TextScanRequest();
        textScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        textScanRequest.setHttpContentType(FormatType.JSON);
        textScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。
        textScanRequest.setEncoding("UTF-8");
        textScanRequest.setRegionId("cn-shanghai");
        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        for (String content : contentList) {
            Map<String, Object> task1 = new LinkedHashMap<String, Object>();
            task1.put("dataId", UUID.randomUUID().toString());
            /**
             * 待检测的文本，长度不超过10000个字符。
             */
            task1.put("content", content);
            tasks.add(task1);
        }

        JSONObject data = new JSONObject();

        /**
         * 检测场景。文本垃圾检测请传递antispam。
         **/
        data.put("scenes", Arrays.asList("antispam"));
        data.put("tasks", tasks);
        System.out.println(JSON.toJSONString(data, true));
        textScanRequest.setHttpContent(data.toJSONString().getBytes(StandardCharsets.UTF_8), "UTF-8", FormatType.JSON);
        // 请务必设置超时时间。
        textScanRequest.setConnectTimeout(3000);
        textScanRequest.setReadTimeout(6000);
        try {
            HttpResponse httpResponse = client.doAction(textScanRequest);
            if(httpResponse.isSuccess()){
                JSONObject scrResponse = JSON.parseObject(new String(httpResponse.getHttpContent(), StandardCharsets.UTF_8));
                ContentCheckDTO contentCheckDTO = JSON.toJavaObject(scrResponse,ContentCheckDTO.class);
                System.out.println(scrResponse.toJSONString());
                if (contentCheckDTO.getCode() == 200) {
                    //生成文本检测记录
                    TextCheckRecordDO textCheckRecordDO = new TextCheckRecordDO();
                    textCheckRecordDO.setUserId(userId);
                    textCheckRecordDO.setTextSource(sourceId);
                    textCheckRecordDO.setContent(contentList.toString());
                    textCheckRecordDO.setResults(contentCheckDTO.getData().toString());
                    textCheckRecordDAO.insertSelective(textCheckRecordDO);
                    boolean flag = true;
                    for (ContentCheckDTO.DataBean dataBean : contentCheckDTO.getData()) {
                        if (dataBean.getResults().get(0).getSuggestion().equals("block")) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        return "pass";
                    } else {
                        return "block";
                    }
                } else {
                    return null;
                }
            }else{
                System.out.println("response not success. status:" + httpResponse.getStatus());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<String> textCheck1(List<String> contentList,Long userId,Integer sourceId) {
        IAcsClient client = getClient();
        TextScanRequest textScanRequest = new TextScanRequest();
        textScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        textScanRequest.setHttpContentType(FormatType.JSON);
        textScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。
        textScanRequest.setEncoding("UTF-8");
        textScanRequest.setRegionId("cn-shanghai");
        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        for (String content : contentList) {
            Map<String, Object> task1 = new LinkedHashMap<String, Object>();
            task1.put("dataId", UUID.randomUUID().toString());
            /**
             * 待检测的文本，长度不超过10000个字符。
             */
            task1.put("content", content);
            tasks.add(task1);
        }

        JSONObject data = new JSONObject();

        /**
         * 检测场景。文本垃圾检测请传递antispam。
         **/
        data.put("scenes", Arrays.asList("antispam"));
        data.put("tasks", tasks);
        textScanRequest.setHttpContent(data.toJSONString().getBytes(StandardCharsets.UTF_8), "UTF-8", FormatType.JSON);
        // 请务必设置超时时间。
        textScanRequest.setConnectTimeout(3000);
        textScanRequest.setReadTimeout(6000);
        HttpResponse httpResponse = null;
        try {
            httpResponse = client.doAction(textScanRequest);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        if(httpResponse.isSuccess()){
            JSONObject scrResponse = JSON.parseObject(new String(httpResponse.getHttpContent(), StandardCharsets.UTF_8));
            ContentCheckDTO contentCheckDTO = JSON.toJavaObject(scrResponse,ContentCheckDTO.class);
            System.out.println(scrResponse.toJSONString());
            if (contentCheckDTO.getCode() == 200) {
                //生成文本检测记录
                TextCheckRecordDO textCheckRecordDO = new TextCheckRecordDO();
                textCheckRecordDO.setUserId(userId);
                textCheckRecordDO.setTextSource(sourceId);
                textCheckRecordDO.setContent(contentList.toString());
                textCheckRecordDO.setResults(contentCheckDTO.getData().toString());
                textCheckRecordDAO.insertSelective(textCheckRecordDO);
                List<String> suggestionList = new LinkedList<>();
                for (ContentCheckDTO.DataBean dataBean : contentCheckDTO.getData()) {
                    if (dataBean.getResults().get(0).getSuggestion().equals("block")) {
                        throw new BusinessErrorException(BusinessCode.CONTAIN_SENSITIVE_WORDS);
                    } else {
                        suggestionList.add(dataBean.getResults().get(0).getSuggestion());
                    }
                }
                return suggestionList;
            } else {
                throw new BusinessErrorException(BusinessCode.SENSITIVE_WORDS_ERROR);
            }
        }else{
            throw new BusinessErrorException(BusinessCode.SENSITIVE_WORDS_ERROR);
        }
    }

    @Override
    public CheckResultDTO singleImageCheck(String filePath, Long userId) {
        IAcsClient client = getClient();

        ImageSyncScanRequest imageSyncScanRequest = new ImageSyncScanRequest();
        // 指定API返回格式。
        imageSyncScanRequest.setAcceptFormat(FormatType.JSON);
        // 指定请求方法。
        imageSyncScanRequest.setMethod(MethodType.POST);
        imageSyncScanRequest.setEncoding("utf-8");
        //支持HTTP和HTTPS。
        imageSyncScanRequest.setProtocol(ProtocolType.HTTP);

        JSONObject httpBody = new JSONObject();
        /**
         * 设置要检测的风险场景。计费依据此处传递的场景计算。
         * 一次请求中可以同时检测多张图片，每张图片可以同时检测多个风险场景，计费按照场景计算。
         * porn：图片智能鉴黄 terrorism：图片暴恐涉政 ad：图文违规 qrcode：图片二维码 live：图片不良场景 logo：图片logo
         * 例如：检测2张图片，场景传递porn和terrorism，计费会按照2张图片鉴黄，2张图片暴恐检测计算。
         * porn：表示鉴黄场景。
         */
        httpBody.put("scenes", Arrays.asList("porn","terrorism","ad"));

        /**
         * 设置待检测图片。一张图片对应一个task。
         * 多张图片同时检测时，处理的时间由最后一个处理完的图片决定。
         * 通常情况下批量检测的平均响应时间比单张检测的要长。一次批量提交的图片数越多，响应时间被拉长的概率越高。
         * 这里以单张图片检测作为示例, 如果是批量图片检测，请自行构建多个task。
         */

        List<JSONObject> tasks = new LinkedList<>();
        JSONObject task = new JSONObject();
        task.put("dataId", UUID.randomUUID().toString());

        //设置图片链接。
        task.put("url", ImageUrl + filePath);
        task.put("time", new Date());
        tasks.add(task);
        httpBody.put("tasks", tasks);

        imageSyncScanRequest.setHttpContent(org.apache.commons.codec.binary.StringUtils.getBytesUtf8(httpBody.toJSONString()),
                "UTF-8", FormatType.JSON);

        /**
         * 请设置超时时间。服务端全链路处理超时时间为10秒，请做相应设置。
         * 如果您设置的ReadTimeout小于服务端处理的时间，程序中会获得一个read timeout异常。
         */
        imageSyncScanRequest.setConnectTimeout(3000);
        imageSyncScanRequest.setReadTimeout(10000);
        HttpResponse httpResponse = null;
        try {
            httpResponse = client.doAction(imageSyncScanRequest);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //服务端接收到请求，完成处理后返回的结果。
        if (httpResponse != null && httpResponse.isSuccess()) {
            JSONObject scrResponse = JSON.parseObject(org.apache.commons.codec.binary.StringUtils.newStringUtf8(httpResponse.getHttpContent()));
            ImageCheckDTO imageCheckDTO = JSON.toJavaObject(scrResponse,ImageCheckDTO.class);
            CheckResultDTO resultDTO = new CheckResultDTO();
            if (imageCheckDTO.getCode() == 200) {
                for (ImageCheckDTO.DataBean dataBean : imageCheckDTO.getData()) {
                    if (dataBean.getCode() == 200) {
                        ContentCheckRecordDO contentCheckRecordDO = new ContentCheckRecordDO();
                        contentCheckRecordDO.setTaskId(dataBean.getTaskId());
                        if (userId != null) {
                            contentCheckRecordDO.setUserId(userId);
                        }
                        for (ImageCheckDTO.DataBean.ResultsBean resultsBean : dataBean.getResults()) {
                            if (resultsBean.getScene().equals("ad")) {
                                resultDTO.setAd(resultsBean.getSuggestion());
                            } else if (resultsBean.getScene().equals("terrorism")) {
                                resultDTO.setTerrorism(resultsBean.getSuggestion());
                            } else {
                                resultDTO.setPorn(resultsBean.getSuggestion());
                            }
                        }
                        contentCheckRecordDO.setResults(JSONObject.toJSONString(dataBean.getResults()));
                        contentCheckRecordDAO.insertSelective(contentCheckRecordDO);
                    } else if (dataBean.getCode() == 404) {
                        throw new BusinessErrorException(BusinessCode.IMAGE_SOURCE_NOT_FIND);
                    }
                }
            }

            return resultDTO;
        } else {
            log.info("阿里云图片检测失败");
            return null;
        }
    }

    /**
     * 视频提交阿里云审核 （当前接口只支持提交单个素材）
     * @param materialId 素材ID
     */
    public void submitSingleVideoCheck(Long materialId) {
        MaterialDO materialDO = materialDAO.selectById(materialId);
        IAcsClient client = getClient();

        VideoAsyncScanRequest videoAsyncScanRequest = new VideoAsyncScanRequest();
        videoAsyncScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        videoAsyncScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。

        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        Map<String, Object> task = new LinkedHashMap<String, Object>();
        task.put("dataId", UUID.randomUUID().toString());
        task.put("url", VideoUrl + materialDO.getFilePath());
        tasks.add(task);

        /**
         * 设置要检测的场景。计费是依据此处传递的场景计算。
         * 视频默认1秒截取一帧，您可以自行控制截帧频率。收费按照视频的截帧数量以及每一帧的检测场景计算。
         * porn：视频智能鉴黄 terrorism：视频暴恐涉政 live：视频不良场景 logo：视频logo ad：视频图文违规
         * 举例：1分钟的视频截帧60张，检测色情（对应场景参数porn）和暴恐涉政（对应场景参数terrorism）2个场景，收费按照60张色情+60张暴恐涉政进行计费。
         */
        JSONObject data = new JSONObject();
        data.put("scenes", Arrays.asList("porn", "terrorism","ad"));
        data.put("tasks", tasks);
        data.put("callback", CallBack);
        data.put("seed", UUID.randomUUID().toString());
        log.info(data.toString());

        videoAsyncScanRequest.setHttpContent(data.toJSONString().getBytes(StandardCharsets.UTF_8), "UTF-8", FormatType.JSON);

        /**
         * 请务必设置超时时间。
         */
        videoAsyncScanRequest.setConnectTimeout(3000);
        videoAsyncScanRequest.setReadTimeout(6000);
        HttpResponse httpResponse = null;
        try {
            httpResponse = client.doAction(videoAsyncScanRequest);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        if(httpResponse.isSuccess()) {
            JSONObject jsonObject = JSON.parseObject(new String(httpResponse.getHttpContent(), StandardCharsets.UTF_8));
            System.out.println(jsonObject.toString());
            SubmitVideoCheckDO submitVideoCheckDO = JSON.toJavaObject(jsonObject, SubmitVideoCheckDO.class);
            if (submitVideoCheckDO.getCode() == 200) {
                for (SubmitVideoCheckDO.DataBean dataBean : submitVideoCheckDO.getData()) {
                    if (dataBean.getCode() == 200) {
                        ContentCheckRecordDO contentCheckRecordDO = new ContentCheckRecordDO();
                        contentCheckRecordDO.setMaterialId(materialId);
                        contentCheckRecordDO.setMaterialUrl(dataBean.getUrl());
                        contentCheckRecordDO.setTaskId(dataBean.getTaskId());
                        contentCheckRecordDO.setUserId(materialDO.getUserId());
                        contentCheckRecordDAO.insertSelective(contentCheckRecordDO);
                    } else {
                        log.info("阿里云提交视频审核失败，错误信息：{}", dataBean.getMsg());
                    }
                }
            }
        }
    }

    /**
     * 阿里云视频审核回调
     * @param request 阿里云请求参数 content checkSum
     * @return CheckResultDTO
     */
    @Override
    public CheckResultDTO callback(Map<String, Object> request) {
        System.out.println(request.get("content"));
        JSONObject content = JSONObject.parseObject((String) request.get("content"));

        VideoCheckCallbackDTO videoCheckCallbackDTO = JSON.toJavaObject(content,VideoCheckCallbackDTO.class);
        if (videoCheckCallbackDTO.getCode() == 200) {
            ContentCheckRecordDO contentCheckRecordDO = contentCheckRecordDAO.selectByTaskId(videoCheckCallbackDTO.getTaskId());
            contentCheckRecordDO.setResults(JSONObject.toJSONString(videoCheckCallbackDTO.getResults()));
            contentCheckRecordDAO.updateSelective(contentCheckRecordDO);

            MaterialDO materialDO = materialDAO.selectById(contentCheckRecordDO.getMaterialId());
            if (materialDO == null) {
                log.info("相关素材已被删除");
                return null;
            }
            boolean flag = true;
            CheckResultDTO checkResultDTO = new CheckResultDTO();
            for (VideoCheckCallbackDTO.ResultsBean resultsBean : videoCheckCallbackDTO.getResults()) {
                if (resultsBean.getScene().equals("ad")) {
                    checkResultDTO.setAd(resultsBean.getSuggestion());
                } else if (resultsBean.getScene().equals("terrorism")) {
                    checkResultDTO.setTerrorism(resultsBean.getSuggestion());
                } else {
                    checkResultDTO.setPorn(resultsBean.getSuggestion());
                }

                if (resultsBean.getSuggestion().equals("block")) {
                    //直接删除素材
                    materialService.deleteMaterial(materialDO.getId());
                    log.info("素材因违规已被删除");
                    return null;
                } else if (resultsBean.getSuggestion().equals("review")) {
                    //需要人工审核
                    flag = false;
                }
            }
            materialDO.setIsCheck(1);
            materialDO.setCheckResult(JSONObject.toJSONString(checkResultDTO));

            if (flag) {
                //直接通过
                materialDO.setNeedReview(0);
            } else {
                //需要人工审核
                materialDO.setNeedReview(1);
            }
            materialDAO.updateSelective(materialDO);
            return checkResultDTO;
        } else {
            log.info("阿里云提交视频审核失败，原因：{}",videoCheckCallbackDTO.getMsg());
            return null;
        }
    }
}
